在 Clojure 中,分布式運算是可以通過庫達成。但在此文,我們講的都是多核心的單一主機的併行。在併發程式設機中,常見的一個情境是阻塞式操作(blocking operation),例如讀取文件,在整個文件讀取完畢前,程式是不會繼續移動的。如果在讀取完畢前,程式就能夠繼續移動,那麼就稱為這是非阻塞,用 Javascript 的術語說,這就叫異步(asynchronously)。
在併發與併行程式設計中,有兩個特別重要的重點:任務分解、風險管理(資料丟失或衝突等)。
JVM 提供自己的一套線程管理功能。所以,Clojure 是使用線程的。在單處理器的情況下,處理器在多個線程之間來回跳躍處理指令。切換線程的時候,另一個線程也被鎖住了。
future
在 Clojure 中,我們若存取一網路資源,例如:
(web-api/get :dwarven-beard-waxes)
程式會暫停以等待完全讀取。不過,我們可以使用 future
,使得結果在被真正需要之前可以繼續執行!
(future (Thread/sleep 4000)
(println "I'll print after 4 seconds"))
(println "I'll print immediately")
理論上,你會先看到 4 seconds 再看到 immediately ,這是因為 sleep
阻斷了繼續逕行。加入了 future 後,阻塞的部分被暫時解除,所以你這次會先看到 immediately 才看到 4 seconds。
在 future
list 中的語句,都會被放到新的線程上。使得原本的線程不被阻塞。但是若尚未被執行完,future
會返回當前執行到的最新一行 list 的結果!
(let [result (future (Thread/sleep 3000)
(+ 1 1))]
(println "The result is: " @result)
(println "It will be at least 3 seconds before I print"))
; => The result is: 2
; => It will be at least 3 seconds before I print